home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectInput / DIConfig / configwnd.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  48.8 KB  |  2,098 lines

  1. //-----------------------------------------------------------------------------
  2. // File: configwnd.cpp
  3. //
  4. // Desc: CConfigWnd is derived from CFlexWnd. It implements the top-level
  5. //       UI window which all other windows are descendents of.
  6. //
  7. //       Functionalities handled by CConfigWnd are device tabs, Reset, Ok,
  8. //       and Cancel buttons.
  9. //
  10. // Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved.
  11. //-----------------------------------------------------------------------------
  12.  
  13. #include "common.hpp"
  14.  
  15.  
  16. LPCTSTR g_tszAppWindowName = _T("DINPUT Default Mapper UI");
  17.  
  18. const int WINDOW_WIDTH = 640;
  19. const int WINDOW_HEIGHT = 480;
  20. const int TABTEXTMARGINLEFT = 7;
  21. const int TABTEXTMARGINTOP = 3;
  22. const int TABTEXTMARGINRIGHT = 7;
  23. const int TABTEXTMARGINBOTTOM = 4;
  24. const int BUTTONTEXTMARGINLEFT = 7;
  25. const int BUTTONTEXTMARGINTOP = 3;
  26. const int BUTTONTEXTMARGINRIGHT = 7;
  27. const int BUTTONTEXTMARGINBOTTOM = 4;
  28. const int BARBUTTONMARGINLEFT = 9;
  29. const int BARBUTTONMARGINTOP = 4;
  30. const int BARBUTTONMARGINRIGHT = 9;
  31. const int BARBUTTONMARGINBOTTOM = 5;
  32. const int BARBUTTONSPACING = 4;
  33.  
  34. //#define WM_QUERYACTIONASSIGNEDANYWHERE (WM_USER + 4)
  35.  
  36.  
  37. CConfigWnd::CConfigWnd(CUIGlobals &uig) :
  38.     m_uig(uig),
  39.     m_bCreated(FALSE),
  40.     m_pPageFactory(NULL),
  41.     m_hPageFactoryInst(NULL),
  42.     m_pSurface(NULL),
  43.     m_pSurface3D(NULL),
  44.     m_CurSel(-1),
  45.     m_nCurGenre(0),
  46.     m_pbmTopGradient(NULL),
  47.     m_pbmBottomGradient(NULL),
  48.     m_pbmPointerEraser(NULL),
  49.     m_pbm3D(NULL),
  50.     m_p3DBits(NULL),
  51.     m_SurfFormat(D3DFMT_UNKNOWN),
  52.     m_uiPixelSize(4),
  53.     m_bBitmapsMapped(FALSE),
  54.     m_lpDI(NULL),
  55.     m_bScrollTabs(FALSE),
  56.     m_bScrollTabsLeft(FALSE),
  57.     m_bScrollTabsRight(FALSE),
  58.     m_nLeftTab(0),
  59.     m_dwInitFlags(0),
  60.     m_bHourGlass(FALSE),
  61.     m_bNeedRedraw(FALSE)
  62. {
  63.     tracescope(__ts, _T("CConfigWnd::CConfigWnd()\n"));
  64.     m_lpDI = m_uig.GetDI();
  65.  
  66.     m_pSurface = m_uig.GetSurface();
  67.     m_pSurface3D = m_uig.GetSurface3D();
  68.  
  69.     if (m_pSurface != NULL || m_pSurface3D != NULL)
  70.     {
  71.         if (m_pSurface != NULL && m_pSurface3D != NULL)
  72.         {
  73.             etrace(_T("Both Surface and Surface3D are non-NULL, will use only Surface3D\n"));
  74.         
  75.             m_pSurface->Release();
  76.             m_pSurface = NULL;
  77.  
  78.             assert(m_pSurface3D != NULL);
  79.             assert(m_pSurface == NULL);
  80.         }
  81.  
  82.         assert(m_pSurface != NULL || m_pSurface3D != NULL);
  83.         assert(!(m_pSurface != NULL && m_pSurface3D != NULL));
  84.  
  85.         m_bRender3D = (m_pSurface3D != NULL);
  86.  
  87.         SetRenderMode();
  88.         trace(_T("RenderMode set\n"));
  89.         traceBOOL(m_bRender3D);
  90.  
  91.         if (m_bRender3D)
  92.             Create3DBitmap();
  93.  
  94.         HDC hDC = GetRenderDC();
  95.         if (hDC != NULL)
  96.         {
  97.             m_pbmPointerEraser = CBitmap::Create(
  98.                 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
  99.                 hDC);
  100.  
  101.             ReleaseRenderDC(hDC);
  102.         }
  103.         else
  104.             etrace(_T("Failed to get Render DC"));
  105.     }
  106. }
  107.  
  108. CConfigWnd::~CConfigWnd()
  109. {
  110.     tracescope(__ts, _T("CConfigWnd::~CConfigWnd()\n"));
  111.     ClearList();
  112.  
  113.     if (m_lpDI != NULL)
  114.         m_lpDI->Release();
  115.     m_lpDI = NULL;
  116.  
  117.     if (m_pSurface != NULL)
  118.         m_pSurface->Release();
  119.     m_pSurface = NULL;
  120.  
  121.     if (m_pSurface3D != NULL)
  122.         m_pSurface3D->Release();
  123.     m_pSurface3D = NULL;
  124.  
  125.     if (m_pPageFactory != NULL)
  126.         m_pPageFactory->Release();
  127.     m_pPageFactory = NULL;
  128.  
  129.     if (m_hPageFactoryInst != NULL)
  130.         FreeLibrary(m_hPageFactoryInst);
  131.     m_hPageFactoryInst = NULL;
  132.  
  133.     if (m_pbmPointerEraser != NULL)
  134.         delete m_pbmPointerEraser;
  135.     m_pbmPointerEraser = NULL;
  136.  
  137.     if (m_pbm3D != NULL)
  138.         delete m_pbm3D;
  139.     m_pbm3D = NULL;
  140.  
  141.     if (m_pbmTopGradient != NULL)
  142.         delete m_pbmTopGradient;
  143.     m_pbmTopGradient = NULL;
  144.  
  145.     if (m_pbmBottomGradient != NULL)
  146.         delete m_pbmBottomGradient;
  147.     m_pbmBottomGradient = NULL;
  148. }
  149.  
  150. HWND CMouseTrap::Create(HWND hParent, BOOL bInRenderMode)
  151. {
  152.     if (m_hWnd)
  153.         return m_hWnd;
  154.  
  155.     m_hParent = hParent;
  156.     int sx = GetSystemMetrics(SM_CXSCREEN);
  157.     int sy = GetSystemMetrics(SM_CYSCREEN);
  158.     RECT rect = {0, 0, sx, sy};
  159.  
  160.     // If we are not in render mode, the trap window is exactly the same as the parent window
  161.     if (!bInRenderMode)
  162.         GetWindowRect(hParent, &rect);
  163.  
  164.     return CFlexWnd::Create(
  165.         hParent,
  166.         NULL,
  167.         WS_EX_TOPMOST,
  168.         WS_POPUP | WS_VISIBLE,
  169.         rect);
  170. }
  171.  
  172. BOOL CConfigWnd::Create(HWND hParent)
  173. {
  174.     tracescope(__ts, _T("CConfigWnd::Create()\n"));
  175.     traceHEX(hParent);
  176.  
  177.     HRESULT hresult = PrivGetClassObject(CLSID_CDIDeviceActionConfigPage, CLSCTX_INPROC_SERVER, NULL,  IID_IClassFactory, (LPVOID*) &m_pPageFactory, &m_hPageFactoryInst);
  178.     if (FAILED(hresult))
  179.     {
  180.         // TODO: indicate failure to create page factory
  181.         m_pPageFactory = NULL;
  182.         m_hPageFactoryInst = NULL;
  183.         etrace1(_T("Failed to create page classfactory, PrivGetClassObject() returned 0x%08x\n"), hresult);
  184.         return FALSE;
  185.     }
  186.  
  187.     int sx = GetSystemMetrics(SM_CXSCREEN);
  188.     int sy = GetSystemMetrics(SM_CYSCREEN);
  189.     int w = WINDOW_WIDTH;
  190.     int h = WINDOW_HEIGHT;
  191.     int rx = sx - w;
  192.     int ry = sy - h;
  193.     RECT rect = {rx / 2, ry / 2, 0, 0};
  194.     rect.right = rect.left + w;
  195.     rect.bottom = rect.top + h;
  196.  
  197.     HWND hConfigParent = hParent;
  198.  
  199.     if (InRenderMode())
  200.     {
  201.         hConfigParent = m_MouseTrap.Create(hParent, InRenderMode());
  202.         if (hConfigParent == NULL)
  203.             hConfigParent = hParent;
  204.     }
  205.  
  206.     HWND hRet = CFlexWnd::Create(
  207.         hConfigParent,
  208.         g_tszAppWindowName,
  209.         0,
  210.         WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN,
  211.         rect);
  212.  
  213.     if (hRet == NULL)
  214.         etrace(_T("CFlexWnd::Create() failed!\n"));
  215.  
  216.     // Set the cursor extent to this window if we are in render mode (full-screen)
  217.     if (InRenderMode())
  218.     {
  219.         RECT rc;
  220.         GetWindowRect(m_hWnd, &rc);
  221.         ClipCursor(&rc);
  222.     }
  223.  
  224.     return NULL != hRet;
  225. }
  226.  
  227. void CConfigWnd::SetForegroundWindow()
  228. {
  229.     // find the window
  230.     HWND hWnd = FindWindow(GetDefaultClassName(), g_tszAppWindowName);
  231.  
  232.     // activate it if found
  233.     if (NULL != hWnd)
  234.         ::SetForegroundWindow(hWnd);
  235. }
  236.  
  237. void CConfigWnd::OnPaint(HDC hDC)
  238. {
  239.     if (hDC == NULL)
  240.         return;
  241.  
  242.     SIZE topsize = GetRectSize(m_rectTopGradient);
  243.     SIZE bottomsize = GetRectSize(m_rectBottomGradient);
  244.     SIZE bsize = {max(topsize.cx, bottomsize.cx),
  245.         max(topsize.cy, bottomsize.cy)};
  246.     CBitmap *pbm = CBitmap::Create(bsize, hDC);
  247.     if (pbm == NULL)
  248.         return;
  249.     HDC hBDC = NULL, hODC = hDC;
  250.     if (m_bHourGlass)
  251.     {
  252.         if (!InRenderMode())
  253.         {
  254.             // If not in fullscreen mode, change cursor to hourglass
  255.             HCURSOR hCursor;
  256.             hCursor = LoadCursor(NULL, IDC_WAIT);
  257.             SetCursor(hCursor);
  258.         } else
  259.         {
  260.             // If in fullscreen mode, hide the cursor during reset process.
  261.             SetCursor(NULL);
  262.         }
  263.     }
  264.  
  265.     hBDC = pbm->BeginPaintInto(hDC);
  266.     if (hBDC == NULL)
  267.     {
  268.         delete pbm;
  269.         return;
  270.     }
  271.     hDC = hBDC;
  272.  
  273.     if (m_pbmTopGradient != NULL)
  274.         m_pbmTopGradient->Draw(hDC);
  275.  
  276.     {
  277.         CPaintHelper ph(m_uig, hDC);
  278.  
  279.         ph.SetElement(UIE_BORDER);
  280.  
  281.         ph.MoveTo(0, m_rectTopGradient.bottom - 1);
  282.         ph.LineTo(WINDOW_WIDTH, m_rectTopGradient.bottom - 1);
  283.  
  284.         int i;
  285.         for (i = 0; i < GetNumElements(); i++)
  286.         {
  287.             const ELEMENT &e = GetElement(i);
  288.             BOOL bSel = i == m_CurSel;
  289.  
  290.             ph.SetElement(bSel ? UIE_SELTAB : UIE_TAB);
  291.  
  292.             ph.Rectangle(e.rect);
  293.             RECT trect = e.textrect;
  294.             DrawText(hDC, e.tszCaption, -1, &trect, DT_NOCLIP | DT_NOPREFIX);
  295.  
  296.             if (bSel)
  297.             {
  298.                 ph.SetPen(UIP_BLACK);
  299.  
  300.                 ph.MoveTo(e.rect.left + 1, e.rect.bottom - 1);
  301.                 ph.LineTo(e.rect.right - 1, e.rect.bottom - 1);
  302.             }
  303.         }
  304.  
  305.         if (m_bScrollTabs && GetNumElements() > 0)
  306.         {
  307.             ph.SetElement(UIE_TABARROW);
  308.  
  309.             const ELEMENT &e = GetElement(0);
  310.             int h = e.rect.bottom - e.rect.top;
  311.  
  312.             for (i = 0; i < 2; i++)
  313.             {
  314.                 RECT &rect = i == 0 ? m_rectSTRight : m_rectSTLeft;
  315.                 BOOL bDraw = i ? m_bScrollTabsLeft : m_bScrollTabsRight;
  316.                 ph.Rectangle(rect);
  317.                 
  318.                 if (!bDraw)
  319.                     continue;
  320.  
  321.                 int d,l,r,m,t,b, f = !i, w;
  322.                 w = rect.right - rect.left;
  323.  
  324.                 l = f ? w / 4 : 3 * w / 8;
  325.                 r = f ? 5 * w / 8 : 3 * w / 4;
  326.                 d = r - l;
  327.                 m = w / 2;
  328.                 t = m - d;
  329.                 b = m + d;
  330.  
  331.                 l += rect.left;
  332.                 r += rect.left;
  333.  
  334.                 POINT p[4];
  335.                 p[3].x = p[0].x = f ? l : r;
  336.                 p[2].x = p[1].x = f ? r : l; 
  337.                 p[3].y = p[0].y = m;
  338.                 p[1].y = t;
  339.                 p[2].y = b;
  340.  
  341.                 Polyline(hDC, p, 4);
  342.             }
  343.         }
  344.     }
  345.  
  346.     pbm->Draw(hODC, topsize);
  347.     m_pbmBottomGradient->Draw(hDC);
  348.  
  349.     {
  350.         CPaintHelper ph(m_uig, hDC);
  351.  
  352.         ph.SetElement(UIE_BORDER);
  353.  
  354.         Rectangle(hDC, 0, -1, WINDOW_WIDTH,
  355.             GetRectSize(m_rectBottomGradient).cy);
  356.  
  357.         for (int i = 0; i < NUMBUTTONS; i++)
  358.         {
  359.             BOOL bOkOnly = !m_uig.InEditMode();
  360.             const BUTTON &b = m_Button[i];
  361.  
  362.  
  363.             if ( bOkOnly && i != BUTTON_CANCEL
  364.                )
  365.                 continue;
  366.  
  367.             if ( (i == BUTTON_OK || bOkOnly)
  368.                )
  369.                 ph.SetElement(UIE_DEFBUTTON);
  370.             else
  371.                 ph.SetElement(UIE_BUTTON);
  372.  
  373.             int ay = m_rectBottomGradient.top;
  374.             ph.Rectangle(b.rect.left, b.rect.top - ay, b.rect.right, b.rect.bottom - ay);
  375.             RECT trect = b.textrect;
  376.             OffsetRect(&trect, 0, -ay);
  377.             DrawText(hDC, b.tszCaption, -1, &trect, DT_NOCLIP | DT_NOPREFIX);
  378.         }
  379.     }
  380.  
  381.     pbm->Draw(hODC, m_rectBottomGradient.left, m_rectBottomGradient.top, bottomsize);
  382.  
  383.     pbm->EndPaintInto(hBDC);
  384.     delete pbm;
  385.  
  386.     hDC = hODC;
  387.  
  388.     {
  389.         CPaintHelper ph(m_uig, hDC);
  390.  
  391.         ph.SetElement(UIE_BORDER);
  392.  
  393.         ph.MoveTo(0, m_rectTopGradient.bottom);
  394.         ph.LineTo(0, m_rectBottomGradient.top);
  395.  
  396.         ph.MoveTo(WINDOW_WIDTH - 1, m_rectTopGradient.bottom);
  397.         ph.LineTo(WINDOW_WIDTH - 1, m_rectBottomGradient.top);
  398.     }
  399. }
  400.  
  401. void CConfigWnd::OnClick(POINT point, WPARAM fwKeys, BOOL bLeft)
  402. {
  403.     int i;
  404.  
  405.     // Un-highlight the current callout
  406.     SendMessage(CFlexWnd::s_CurrPageHwnd, WM_UNHIGHLIGHT, 0, 0);
  407.  
  408.     // check scroll tab buttons
  409.     if (m_bScrollTabs)
  410.         for (i = 0; i < 2; i++)
  411.         {
  412.             RECT &r = !i ? m_rectSTRight : m_rectSTLeft;
  413.             BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft;
  414.             if (PtInRect(&r, point))
  415.             {
  416.                 if (b)
  417.                     ScrollTabs(!i ? -1 : 1);
  418.                 return;
  419.             }
  420.         }
  421.  
  422.     // check tabs
  423.     for (i = 0; i < GetNumElements(); i++)
  424.         if (PtInRect(&(GetElement(i).rect), point))
  425.         {
  426.             // Check if the tab is partially obscured.  If so we scroll the tab so it becomes completely visible.
  427.             POINT pt = {m_rectSTLeft.left, m_rectSTLeft.top};
  428.             if (m_bScrollTabsRight || m_bScrollTabsLeft)
  429.             {
  430.                 while (PtInRect(&(GetElement(i).rect), pt))
  431.                     ScrollTabs(1);
  432.             }
  433.             SelTab(i);
  434.             return;
  435.         }
  436.  
  437.     // check buttons
  438.     for (i = 0; i < NUMBUTTONS; i++)
  439.         if (PtInRect(&(m_Button[i].rect), point))
  440.         {
  441.             FireButton(i);
  442.             return;
  443.         }
  444. }
  445.  
  446. void CConfigWnd::ScrollTabs(int by)
  447. {
  448.     m_nLeftTab += by;
  449.     if (m_nLeftTab < 0)
  450.         m_nLeftTab = 0;
  451.     if (m_nLeftTab >= GetNumElements())
  452.         m_nLeftTab = GetNumElements() - 1;
  453.     CalcTabs();
  454.     Invalidate();
  455. }
  456.  
  457. void CConfigWnd::OnDestroy()
  458. {
  459.     tracescope(__ts, _T("CConfigWnd::OnDestroy()\n"));
  460.     ClipCursor(NULL);  // Set cursor extent to entire desktop.
  461.     if (m_bCreated)
  462.         PostQuitMessage(EXIT_SUCCESS);
  463. }
  464.  
  465. LRESULT CConfigWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  466. {
  467.     tracescope(__ts, _T("CConfigWnd::OnCreate()\n"));
  468.  
  469.     if (!Init())
  470.     {
  471.         etrace(_T("CConfigWnd::Init() failed\n"));
  472.         return -1;
  473.     }
  474.     else
  475.         m_bCreated = TRUE;
  476.  
  477.     return 0;
  478. }
  479.  
  480. BOOL CALLBACK EnumDeviceCallback(const DIDEVICEINSTANCEW *lpdidi, LPDIRECTINPUTDEVICE8W pdiDev8W, DWORD dwFlags, DWORD dwDeviceRemaining, LPVOID pvRef)
  481. {
  482.     if (pvRef != NULL)
  483.         return ((CConfigWnd *)pvRef)->EnumDeviceCallback(lpdidi);
  484.     else
  485.         return DIENUM_STOP;
  486. }
  487.  
  488. BOOL CConfigWnd::EnumDeviceCallback(const DIDEVICEINSTANCEW *lpdidi)
  489. {
  490.     DIDEVICEINSTANCEW didi;
  491.     didi.dwSize = sizeof(DIDEVICEINSTANCEW);
  492.     didi.guidInstance = lpdidi->guidInstance;
  493.     didi.guidProduct = lpdidi->guidProduct;
  494.     didi.dwDevType = lpdidi->dwDevType;
  495.     CopyStr(didi.tszInstanceName, lpdidi->tszInstanceName, MAX_PATH);
  496.     CopyStr(didi.tszProductName, lpdidi->tszProductName, MAX_PATH);
  497.     didi.guidFFDriver = lpdidi->guidFFDriver;
  498.     didi.wUsagePage = lpdidi->wUsagePage;
  499.     didi.wUsage = lpdidi->wUsage;
  500.  
  501.     AddToList(&didi);
  502.  
  503.     return DIENUM_CONTINUE;
  504. }
  505.  
  506. // show any error message here if returning false
  507. BOOL CConfigWnd::Init(DWORD dwInitFlags)
  508. {
  509.     tracescope(__ts, _T("CConfigWnd::Init()\n"));
  510.  
  511.     HRESULT hr = S_OK;
  512.     BOOL bReInit = !!(dwInitFlags & CFGWND_INIT_REINIT);
  513.  
  514.     m_dwInitFlags = dwInitFlags;
  515.     SetOnFunctionExit<DWORD> _set_m_dwInitFlags(m_dwInitFlags, 0);
  516.  
  517.     // make sure we have DI
  518.     assert(m_lpDI != NULL);
  519.     if (m_lpDI == NULL)
  520.     {
  521.         etrace(_T("NULL m_lpDI\n"));
  522.         return FALSE;
  523.     }
  524.  
  525.     if (!(dwInitFlags & CFGWND_INIT_RESET))
  526.     {
  527.         // If we are not doing reset, clear device list then re-enumerate and rebuild.
  528.  
  529.         // clear list
  530.         ClearList();
  531.  
  532.         // enum devices
  533.         {
  534.             tracescope(ts, _T("Enumerating Devices...\n\n"));
  535.  
  536.             DWORD dwFlags = DIEDBSFL_ATTACHEDONLY;
  537.             hr = m_lpDI->EnumDevicesBySemantics(NULL, (LPDIACTIONFORMATW)&m_uig.RefMasterAcFor(m_nCurGenre), ::EnumDeviceCallback, (LPVOID)this, dwFlags);
  538.  
  539.             trace(_T("\n"));
  540.         }
  541.     } else
  542.     {
  543.         DIDEVICEINSTANCEW didiCopy;
  544.         // Saves a copy of device instance as the current ELEMENT will be freed by AddToList().
  545.         CopyMemory(&didiCopy, &GetElement(m_CurSel).didi, sizeof(didiCopy));
  546.         // If resetting, call AddToList with bReset as TRUE to just get default mappings.
  547.         AddToList(&didiCopy, TRUE);
  548.     }
  549.  
  550.     // handle potential enum failure
  551.     if (FAILED(hr))
  552.     {
  553.         etrace1(_T("EnumDevicesBySemantics() failed, returning 0x%08x\n"), hr);
  554.         return FALSE;
  555.     }
  556.  
  557.     // if there are no elements, fail
  558.     if (GetNumElements() < 1)
  559.     {
  560.         etrace(_T("No devices\n"));
  561.         return FALSE;
  562.     }
  563.  
  564.     // calculate tabs, buttons, init gradients
  565.     CalcTabs();
  566.     if (!bReInit)
  567.     {
  568.         CalcButtons();
  569.         InitGradients();
  570.  
  571.         // set the timer
  572.         if (InRenderMode())
  573.         {
  574.             if (g_fptimeSetEvent)
  575.                 g_fptimeSetEvent(20, 20, CConfigWnd::TimerProc,
  576.                                  (DWORD_PTR)m_hWnd, TIME_ONESHOT);
  577.             Render();
  578.         }
  579.     }
  580.  
  581.     // make sure all the pages are in the right place
  582.     PlacePages();
  583.  
  584.     // show the first page if we are not resetting. Show current page if we are.
  585.     int CurSel = (dwInitFlags & CFGWND_INIT_RESET) ? m_CurSel : 0;
  586.     m_CurSel = -1;
  587.     SelTab(CurSel);
  588.  
  589.     // if we're already editting the layout, set it.
  590.     // KLUDGE, set false and toggle to set
  591.     if (m_bEditLayout)
  592.     {
  593.         m_bEditLayout = FALSE;
  594.         ToggleLayoutEditting();
  595.     }
  596.  
  597.     trace(_T("\n"));
  598.  
  599.     return TRUE;
  600. }
  601.  
  602. // This is called once for each device that will get configured.
  603. int CConfigWnd::AddToList(const DIDEVICEINSTANCEW *lpdidi, BOOL bReset)
  604. {
  605.     if (lpdidi == NULL)
  606.     {
  607.         etrace(_T("NULL lpdidi"));
  608.         assert(0);
  609.         return GetNumElements();
  610.     }
  611.  
  612.     int i;
  613.  
  614.     tracescope(ts, _T("Adding Device "));
  615.     trace(QSAFESTR(lpdidi->tszInstanceName));
  616.     trace(_T("\n\n"));
  617.  
  618.     // add an element and get it if we are not doing reset (adding new device)
  619.     if (!bReset)
  620.     {
  621.         i = GetNumElements();
  622.         m_Element.SetSize(i + 1);
  623.     }
  624.     else
  625.     {
  626.         i = m_CurSel;
  627.         ClearElement(m_CurSel, bReset);  // If resetting, clear the current ELEMENT as we will populate it below.
  628.     }
  629.  
  630.     // If we are doing reset, then we use the existing ELEMENT that this device is already using.
  631.     ELEMENT &e = bReset ? GetElement(m_CurSel) : GetElement(i);
  632.  
  633.     // set various needed variables
  634.     e.didi = *lpdidi;
  635.     e.bCalc = FALSE;
  636.     e.pUIGlobals = &m_uig;
  637.  
  638.     // create and set the device
  639.     if (m_lpDI == NULL)
  640.     {
  641.         e.lpDID = NULL;
  642.         etrace(_T("m_lpDI NULL!  Can't create this device.\n"));
  643.     }
  644.     else
  645.     {
  646.         e.lpDID = CreateDevice(e.didi.guidInstance);
  647.         if (!e.lpDID)
  648.             etrace(_T("Failed to create device!\n"));
  649.     }
  650.  
  651.     if (!bReset)
  652.     {
  653.         // Find owner of device only if we are not doing reset.
  654.         // set starting current user index
  655.         DIPROPSTRING dips;
  656.         dips.diph.dwSize = sizeof(DIPROPSTRING);
  657.         dips.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  658.         dips.diph.dwObj = DIPH_DEVICE;
  659.         dips.diph.dwHow = 0;
  660.         CopyStr(dips.wsz, "", MAX_PATH);
  661.         if (!e.lpDID)
  662.         {
  663.             etrace(_T("no lpDID, assuming device unassigned\n"));
  664.             e.nCurUser = -1;
  665.         }
  666.         else
  667.         {
  668.             HRESULT hr = e.lpDID->GetProperty(DIPROP_USERNAME, (LPDIPROPHEADER)&dips);
  669.             e.nCurUser = -1; // unassigned unless getusernameindex below works
  670.             if (FAILED(hr))
  671.                 etrace(_T("GetProperty(DIPROP_USERNAME,...) failed\n"));
  672.             else if (hr == S_FALSE)
  673.                 trace(_T("GetProperty(DIPROP_USERNAME,...) returned S_FALSE\n"));
  674.             else if (StrLen(dips.wsz) < 1)
  675.                 trace(_T("GetProperty(DIPROP_USERNAME,...) returned empty string\n"));
  676.             else
  677.             {
  678.                 trace(_T("Getting user name index for "));
  679.                 traceWSTR(dips.wsz);
  680.                 e.nCurUser = m_uig.GetUserNameIndex(dips.wsz);
  681.                 trace(_T("Result: "));
  682.                 traceLONG(e.nCurUser);
  683.                 if (e.nCurUser == -1)
  684.                     etrace(_T("Device assigned to user not passed to ConfigureDevices()\nConsidering unassigned now\n"));
  685.             }
  686.         }
  687.     }
  688.  
  689.     // create and set the page object
  690.     HWND hwndChild = NULL;
  691.     e.pPage = CreatePageObject(i, e, hwndChild);
  692.     if (e.pPage == NULL)
  693.         etrace(_T("Failed to create page object!\n"));
  694.     e.hWnd = hwndChild;
  695.     if (e.hWnd == NULL)
  696.         etrace(_T("CreatePageObject() returned NULL hwnd!\n"));
  697.  
  698.     // create/test the first acfor for this device with cur genre/user
  699.     traceLONG(m_nCurGenre);
  700.     traceLONG(e.nCurUser);
  701.     LPDIACTIONFORMATW lpAcFor = NULL;
  702.     if (e.nCurUser != -1)
  703.     {
  704.         lpAcFor = e.GetAcFor(m_nCurGenre, e.nCurUser, bReset);
  705.         if (lpAcFor != NULL)
  706.             TraceActionFormat(_T("Starting Device ActionFormat:"), *lpAcFor);
  707.         else
  708.             etrace(_T("Failed to create starting ActionFormat\n"));
  709.     }
  710.     else
  711.         trace(_T("Device unassigned\n"));
  712.  
  713.     // check if anything was unsuccessful
  714.     if ((lpAcFor == NULL && e.nCurUser != -1) || e.lpDID == NULL || e.pPage == NULL || e.hWnd == NULL)
  715.     {
  716.         // clear what was successful, set the size back (remove element),
  717.         // and indicate error
  718.         ClearElement(e);
  719.         m_Element.SetSize(i);
  720.         etrace(_T("Can't add this device - Element removed\n"));
  721.     }
  722.  
  723.     trace(_T("\n"));
  724.  
  725.     return GetNumElements();
  726. }
  727.  
  728. LPDIRECTINPUTDEVICE8W CConfigWnd::CreateDevice(GUID &guid)
  729. {
  730.     LPDIRECTINPUTDEVICE8W lpDID;
  731.  
  732.     HRESULT hr = m_lpDI->CreateDevice(guid, &lpDID, NULL);
  733.     if (FAILED(hr) || lpDID == NULL)
  734.     {
  735.         etrace2(_T("Could not create device (guid %s), CreateDevice() returned 0x%08x\n"), GUIDSTR(guid), hr);
  736.         return NULL;
  737.     }
  738.     
  739.     return lpDID;
  740. }
  741.  
  742. void CConfigWnd::ClearElement(int i, BOOL bReset)
  743. {
  744.     ELEMENT &e = GetElement(i);
  745.     ClearElement(e, bReset);
  746. }
  747.  
  748. void CConfigWnd::ClearElement(ELEMENT &e, BOOL bReset)
  749. {
  750.     if (e.pPage != NULL)
  751.         DestroyPageObject(e.pPage);
  752.     if (e.lpDID != NULL)
  753.     {
  754.         e.lpDID->Release();
  755.         e.lpDID = NULL;
  756.     }
  757.     e.pPage = NULL;
  758.     e.lpDID = NULL;
  759.     e.hWnd = NULL;
  760.     e.pUIGlobals = NULL; // not freed
  761.     if (!bReset)  // Free map only if we are not resetting (delete permanently).
  762.         e.FreeMap();
  763. }
  764.  
  765. void CConfigWnd::ClearList()
  766. {
  767.     int i;
  768.     for (i = 0; i < GetNumElements(); i++)
  769.         ClearElement(i);
  770.     m_Element.RemoveAll();
  771.     assert(!GetNumElements());
  772. }
  773.  
  774. void CConfigWnd::PlacePages()
  775. {
  776.     RECT rect;
  777.     GetPageRect(rect);
  778.  
  779.     for (int i = 0; i < GetNumElements(); i++)
  780.     {
  781.         DWORD flags = SWP_NOZORDER | SWP_NOACTIVATE;
  782.         SetWindowPos(GetElement(i).hWnd, NULL,
  783.             rect.left, rect.top,
  784.             rect.right - rect.left,
  785.             rect.bottom - rect.top, flags);
  786.     }
  787. }
  788.  
  789. SIZE CConfigWnd::GetTextSize(LPCTSTR tszText)
  790. {
  791.     RECT trect = {0, 0, 1, 1};
  792.     HDC hDC = CreateCompatibleDC(NULL);
  793.     if (hDC != NULL)
  794.     {
  795.         {
  796.             CPaintHelper ph(m_uig, hDC);
  797.             ph.SetFont(UIF_FRAME);
  798.             DrawText(hDC, tszText, -1, &trect, DT_CALCRECT | DT_NOPREFIX);
  799.         }
  800.         DeleteDC(hDC);
  801.     }
  802.     SIZE size = {trect.right - trect.left, trect.bottom - trect.top};
  803.     return size;
  804. }
  805.  
  806. void CConfigWnd::InitGradients()
  807. {
  808.     if (m_pbmTopGradient == NULL)
  809.         m_pbmTopGradient = CBitmap::CreateHorzGradient(m_rectTopGradient, m_uig.GetColor(UIC_CONTROLFILL), m_uig.GetColor(UIC_CONTROLFILL));
  810.     if (m_pbmBottomGradient == NULL)
  811.         m_pbmBottomGradient = CBitmap::CreateHorzGradient(m_rectBottomGradient, m_uig.GetColor(UIC_CONTROLFILL), m_uig.GetColor(UIC_CONTROLFILL));
  812. }
  813.  
  814. void CConfigWnd::CalcTabs()
  815. {
  816.     int i, maxh = 0, lastx = 0;
  817.     for (i = 0; i < GetNumElements(); i++)
  818.     {
  819.         ELEMENT &e = GetElement(i);
  820.         CopyStr(e.tszCaption, e.didi.tszInstanceName, MAX_PATH);
  821.         e.rect.left = i > 0 ? GetElement(i - 1).rect.right - 1 : 0;
  822.         e.rect.top = 0;
  823.         SIZE tsize = GetTextSize(e.tszCaption);
  824.         e.textrect.left = e.textrect.top = 0;
  825.         e.textrect.right = tsize.cx;
  826.         e.textrect.bottom = tsize.cy;
  827.         OffsetRect(&e.textrect, e.rect.left + TABTEXTMARGINLEFT, e.rect.top + TABTEXTMARGINTOP);
  828.         int w = tsize.cx;
  829.         int h = tsize.cy;
  830.         e.rect.right = e.rect.left + TABTEXTMARGINLEFT + w + TABTEXTMARGINRIGHT + 1;
  831.         e.rect.bottom = e.rect.top + TABTEXTMARGINTOP + h + TABTEXTMARGINBOTTOM;
  832.         h = e.rect.bottom - e.rect.top;
  833.         if (h > maxh) maxh = h;
  834.         e.bCalc = TRUE;
  835.     }
  836.  
  837.     for (i = 0; i < GetNumElements(); i++)
  838.     {
  839.         ELEMENT &e = GetElement(i);
  840.         e.rect.bottom = e.rect.top + maxh;
  841.         lastx = e.rect.right;
  842.     }
  843.  
  844.     if (lastx > WINDOW_WIDTH)
  845.     {
  846.         if (!m_bScrollTabs)
  847.             m_nLeftTab = 0;
  848.         m_bScrollTabs = TRUE;
  849.     }
  850.     else
  851.     {
  852.         m_bScrollTabs = FALSE;
  853.         m_nLeftTab = 0;
  854.     }
  855.  
  856.     int cutoff = WINDOW_WIDTH;
  857.     if (m_bScrollTabs)
  858.     {
  859.         cutoff = WINDOW_WIDTH - maxh * 2;
  860.         RECT r = {WINDOW_WIDTH - maxh, 0, WINDOW_WIDTH, maxh};
  861.         m_rectSTLeft = r;
  862.         OffsetRect(&r, -(maxh - 1), 0);
  863.         m_rectSTRight = r;
  864.     }
  865.  
  866.     if (m_bScrollTabs && m_nLeftTab > 0)
  867.     {
  868.         int left = GetElement(m_nLeftTab).rect.left, right = 0;
  869.         for (i = 0; i < GetNumElements(); i++)
  870.         {
  871.             ELEMENT &e = GetElement(i);
  872.             OffsetRect(&e.rect, -left, 0);
  873.             OffsetRect(&e.textrect, -left, 0);
  874.             if (e.rect.right > right)
  875.                 right = e.rect.right;
  876.         }
  877.         lastx = right;
  878.     }
  879.  
  880.     if (m_bScrollTabs)
  881.     {
  882.         m_bScrollTabsLeft = lastx > cutoff && m_nLeftTab < GetNumElements() - 1;
  883.         m_bScrollTabsRight = m_nLeftTab > 0;
  884.     }
  885.  
  886.     RECT t = {0/*lastx*/, 0, WINDOW_WIDTH, maxh};
  887.     m_rectTopGradient = t;
  888. }
  889.  
  890. void CConfigWnd::CalcButtons()
  891. {
  892.     SIZE max = {0, 0};
  893.     int i;
  894.     for (i = 0; i < NUMBUTTONS; i++)
  895.     {
  896.         BUTTON &b = m_Button[i];
  897.  
  898.         if (!StrLen(b.tszCaption))
  899.         {
  900.             switch (i)
  901.             {
  902.                 case BUTTON_RESET:
  903.                 LoadString(g_hModule, IDS_BUTTON_RESET, b.tszCaption, MAX_PATH);
  904.                 break;
  905.  
  906.  
  907.             case BUTTON_CANCEL:
  908.                 if (m_uig.InEditMode())
  909.                 {
  910.                     LoadString(g_hModule, IDS_BUTTON_CANCEL, b.tszCaption, MAX_PATH);
  911.                     break;
  912.                 }
  913.                 // else, intentional fallthrough
  914.  
  915.             case BUTTON_OK:
  916.                 LoadString(g_hModule, IDS_BUTTON_OK, b.tszCaption, MAX_PATH);
  917.                 break;
  918.             }
  919.         }
  920.  
  921.         b.textsize = GetTextSize(b.tszCaption);
  922.  
  923.         if (b.textsize.cx > max.cx)
  924.             max.cx = b.textsize.cx;
  925.         if (b.textsize.cy > max.cy)
  926.             max.cy = b.textsize.cy;
  927.     }
  928.  
  929.     max.cx += BUTTONTEXTMARGINLEFT + BUTTONTEXTMARGINRIGHT;
  930.     max.cy += BUTTONTEXTMARGINTOP + BUTTONTEXTMARGINBOTTOM;
  931.  
  932.     m_rectBottomGradient.bottom = WINDOW_HEIGHT;
  933.     m_rectBottomGradient.top = m_rectBottomGradient.bottom - max.cy - BARBUTTONMARGINTOP - BARBUTTONMARGINBOTTOM;
  934.     m_rectBottomGradient.left = 0;
  935.     m_rectBottomGradient.right = WINDOW_WIDTH;
  936.  
  937.     for (i = 0; i < NUMBUTTONS; i++)
  938.     {
  939.         BUTTON &b = m_Button[i];
  940.  
  941.         RECT z = {0,0,0,0};
  942.  
  943.         b.rect = z;
  944.         b.rect.right = max.cx;
  945.         b.rect.bottom = max.cy;
  946.  
  947.         int by = m_rectBottomGradient.top + BARBUTTONMARGINTOP;
  948.  
  949.         switch (i)
  950.         {
  951.             case BUTTON_RESET:
  952.                 OffsetRect(&b.rect, BARBUTTONMARGINLEFT, by);
  953.                 break;
  954.  
  955.  
  956.             case BUTTON_CANCEL:
  957.                 OffsetRect(&b.rect,
  958.                 m_rectBottomGradient.right - BARBUTTONMARGINRIGHT - max.cx, by);
  959.                 break;
  960.  
  961.             case BUTTON_OK:
  962.                 OffsetRect(&b.rect,
  963.                 m_rectBottomGradient.right - BARBUTTONMARGINRIGHT - max.cx - max.cx - BARBUTTONSPACING, by);
  964.                 break;
  965.         }
  966.  
  967.         POINT m = {(b.rect.right + b.rect.left) / 2, (b.rect.bottom + b.rect.top) / 2};
  968.         b.textrect.left = m.x - b.textsize.cx / 2;
  969.         b.textrect.top = m.y - b.textsize.cy / 2;
  970.         b.textrect.right = b.textrect.left + b.textsize.cx;
  971.         b.textrect.bottom = b.textrect.top + b.textsize.cy;
  972.     }
  973. }
  974.  
  975. void CConfigWnd::GetPageRect(RECT &rect, BOOL bTemp)
  976. {
  977.     if (bTemp)
  978.     {
  979.         rect.left = 1;
  980.         rect.right = WINDOW_WIDTH - 1;
  981.         rect.top = 40;
  982.         rect.bottom = WINDOW_HEIGHT - 40;
  983.     }
  984.     else
  985.     {
  986.         rect.left = 1;
  987.         rect.right = WINDOW_WIDTH - 1;
  988.         rect.top = m_rectTopGradient.bottom;
  989.         rect.bottom = m_rectBottomGradient.top;
  990.     }
  991. }
  992.  
  993. void CConfigWnd::ToggleLayoutEditting()
  994. {
  995.     m_bEditLayout = !m_bEditLayout;
  996.  
  997.     for (int i = 0; i < GetNumElements(); i++)
  998.     {
  999.         ELEMENT &e = GetElement(i);
  1000.         if (e.pPage)
  1001.             e.pPage->SetEditLayout(m_bEditLayout);
  1002.     }
  1003. }
  1004.  
  1005. void CConfigWnd::FireButton(int b)
  1006. {
  1007.     switch(b)
  1008.     {
  1009.         case BUTTON_OK:
  1010.             if (!m_uig.InEditMode())
  1011.                 break;  // If not in edit mode, Ok button doesn't not exist so we shouldn't do anything.
  1012.                 Apply();  // If we are in Edit Layout mode, do not call Apply() to save to user setting.
  1013.             // intentional fallthrough
  1014.  
  1015.         case BUTTON_CANCEL:
  1016.             Destroy();
  1017.             break;
  1018.  
  1019.         case BUTTON_RESET:
  1020.             if (m_uig.InEditMode())  // Only reset if in edit mode.  Do nothing in view mode.
  1021.                 Reset();
  1022.             break;
  1023.  
  1024.  
  1025.         default:
  1026.             assert(0);
  1027.             break;
  1028.     }
  1029. }
  1030.  
  1031. void CConfigWnd::SelTab(int i)
  1032. {
  1033.     if (i >= 0 && i < GetNumElements())
  1034.     {
  1035.         if (i == m_CurSel)
  1036.             return;
  1037.         ShowPage(i);
  1038.         HidePage(m_CurSel);
  1039.         m_CurSel = i;
  1040.         Invalidate();
  1041.     }
  1042. }
  1043.  
  1044. PAGETYPE *CConfigWnd::CreatePageObject(int nPage, const ELEMENT &e, HWND &refhChildWnd)
  1045. {
  1046.     if (m_pPageFactory == NULL)
  1047.         return NULL;
  1048.  
  1049.     PAGETYPE *pPage = NULL;
  1050.     HRESULT hresult = m_pPageFactory->CreateInstance(NULL, IID_IDIDeviceActionConfigPage, (LPVOID*) &pPage);
  1051.     if (FAILED(hresult) || pPage == NULL)
  1052.         return NULL;
  1053.  
  1054.     DICFGPAGECREATESTRUCT cs;
  1055.     cs.dwSize = sizeof(DICFGPAGECREATESTRUCT);
  1056.     cs.nPage = nPage;
  1057.     cs.hParentWnd = m_hWnd;
  1058.     GetPageRect(cs.rect, TRUE);
  1059.     cs.hPageWnd = NULL;
  1060.     cs.didi = e.didi;
  1061.     cs.lpDID = e.lpDID;
  1062.     cs.pUIGlobals = &m_uig;
  1063.     cs.pUIFrame = dynamic_cast<IDIConfigUIFrameWindow *>(this);
  1064.  
  1065.     hresult = pPage->Create(&cs);
  1066.     if (FAILED(hresult))
  1067.     {
  1068.         etrace1(_T("pPage->Create() failed, returning 0x%08x\n"), hresult);
  1069.         pPage->Release();
  1070.         return NULL;
  1071.     }
  1072.  
  1073.     refhChildWnd = cs.hPageWnd;
  1074.  
  1075.     return pPage;
  1076. }
  1077.  
  1078. void CConfigWnd::DestroyPageObject(PAGETYPE *&pPage)
  1079. {
  1080.     if (pPage != NULL)
  1081.         pPage->Release();
  1082.     pPage = NULL;
  1083. }
  1084.  
  1085. void CConfigWnd::ShowPage(int i)
  1086. {
  1087.     if (i == -1)
  1088.         return;
  1089.  
  1090.     if (i < 0 || i >= GetNumElements())
  1091.     {
  1092.         assert(0);
  1093.         return;
  1094.     }
  1095.  
  1096.     ELEMENT &e = GetElement(i);
  1097.  
  1098.     PAGETYPE *pPage = e.pPage;
  1099.     if (pPage == NULL)
  1100.     {
  1101.         assert(0);
  1102.         return;
  1103.     }
  1104.  
  1105.     pPage->Show(e.GetAcFor(m_nCurGenre, e.nCurUser));
  1106. }
  1107.  
  1108. void CConfigWnd::HidePage(int i)
  1109. {
  1110.     if (i == -1)
  1111.         return;
  1112.  
  1113.     if (i < 0 || i >= GetNumElements())
  1114.     {
  1115.         assert(0);
  1116.         return;
  1117.     }
  1118.  
  1119.     PAGETYPE *pPage = GetElement(i).pPage;
  1120.     if (pPage == NULL)
  1121.     {
  1122.         assert(0);
  1123.         return;
  1124.     }
  1125.  
  1126.     pPage->Hide();
  1127. }
  1128.  
  1129. void CConfigWnd::OnMouseOver(POINT point, WPARAM fwKeys)
  1130. {
  1131.     int i;
  1132.  
  1133.     CFlexWnd::s_ToolTip.SetEnable(FALSE);
  1134.  
  1135.     // check scroll tab buttons
  1136.     if (m_bScrollTabs)
  1137.         for (i = 0; i < 2; i++)
  1138.         {
  1139.             RECT &r = !i ? m_rectSTRight : m_rectSTLeft;
  1140.             BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft;
  1141.             if (PtInRect(&r, point))
  1142.             {
  1143.                 if (b)
  1144.                     GetElement(m_CurSel).pPage->SetInfoText(m_uig.InEditMode() ? IDS_INFOMSG_EDIT_TABSCROLL : IDS_INFOMSG_VIEW_TABSCROLL);
  1145.                 return;
  1146.             }
  1147.         }
  1148.  
  1149.     // check tabs
  1150.     for (i = 0; i < GetNumElements(); i++)
  1151.         if (PtInRect(&(GetElement(i).rect), point))
  1152.         {
  1153.             GetElement(m_CurSel).pPage->SetInfoText(m_uig.InEditMode() ? IDS_INFOMSG_EDIT_TAB : IDS_INFOMSG_VIEW_TAB);
  1154.             return;
  1155.         }
  1156.  
  1157.     // check buttons
  1158.     for (i = 0; i < NUMBUTTONS; i++)
  1159.         if (PtInRect(&(m_Button[i].rect), point))
  1160.         {
  1161.             switch(i)
  1162.             {
  1163.                 case BUTTON_OK:
  1164.                     if (m_uig.InEditMode())
  1165.                         GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_OK);
  1166.                     break;
  1167.  
  1168.                 case BUTTON_CANCEL:
  1169.                     if (m_uig.InEditMode())
  1170.                         GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_CANCEL);
  1171.                     else
  1172.                         GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_VIEW_OK);
  1173.                     break;
  1174.  
  1175.                 case BUTTON_RESET:
  1176.                     if (m_uig.InEditMode())  // Only reset if in edit mode.  Do nothing in view mode.
  1177.                         GetElement(m_CurSel).pPage->SetInfoText(IDS_INFOMSG_EDIT_RESET);
  1178.                     break;
  1179.             }
  1180.             return;
  1181.         }
  1182.  
  1183.     GetElement(m_CurSel).pPage->SetInfoText(-1);
  1184. }
  1185.  
  1186. void CALLBACK CConfigWnd::TimerProc(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
  1187. {
  1188.     if (!IsWindow((HWND)dwUser)) return;  // Verify that dwUser is a valid window handle
  1189.     CConfigWnd *pCfgWnd = (CConfigWnd *)GetFlexWnd((HWND)dwUser);  // Get flex object
  1190.  
  1191.     // We use PostMessage instead of calling Render() so we stay synchronized.
  1192.     PostMessage((HWND)dwUser, WM_DIRENDER, 0, 0);
  1193. }
  1194.  
  1195. void CConfigWnd::MapBitmaps(HDC hDC)
  1196. {
  1197.     if (m_bBitmapsMapped)
  1198.         return;
  1199.  
  1200.     if (m_pbmTopGradient)
  1201.         m_pbmTopGradient->MapToDC(hDC);
  1202.     if (m_pbmBottomGradient)
  1203.         m_pbmBottomGradient->MapToDC(hDC);
  1204.  
  1205.     m_bBitmapsMapped = TRUE;
  1206. }
  1207.  
  1208. LPDIACTIONFORMATW CConfigWnd::GetCurAcFor(ELEMENT &e)
  1209. {
  1210.     return e.GetAcFor(m_nCurGenre, e.nCurUser);
  1211. }
  1212.  
  1213. BOOL CConfigWnd::IsActionAssignedAnywhere(GUID GuidInstance, int nActionIndex)
  1214. {
  1215.     // Find out which user owns the device in question first.
  1216.     int nUser = 0;
  1217.     for (int ii = 0; ii < GetNumElements(); ii++)
  1218.     {
  1219.         ELEMENT &e = GetElement(ii);
  1220.         if (IsEqualGUID(e.didi.guidInstance, GuidInstance))
  1221.         {
  1222.             nUser = e.nCurUser;
  1223.             break;
  1224.         }
  1225.     }
  1226.  
  1227.     // Now we check the actions against this user.
  1228.     for (int i = 0; i < GetNumElements(); i++)
  1229.     {
  1230.         ELEMENT &e = GetElement(i);
  1231.         const LPDIACTIONFORMATW &lpAcFor = e.GetAcFor(m_nCurGenre, nUser);
  1232.  
  1233.         if (lpAcFor == NULL)
  1234.             continue;
  1235.  
  1236.         if (nActionIndex < 0 || nActionIndex > int(lpAcFor->dwNumActions))
  1237.             continue;
  1238.  
  1239.         // If this device is not owned by this user, don't need to check.
  1240.         if (e.nCurUser != nUser)
  1241.             continue;
  1242.  
  1243.         const DIACTIONW &a = lpAcFor->rgoAction[nActionIndex];
  1244.  
  1245.         if (!IsEqualGUID(a.guidInstance, GUID_NULL))
  1246.             return TRUE;
  1247.     }
  1248.  
  1249.     return FALSE;
  1250. }
  1251.  
  1252. LRESULT CConfigWnd::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1253. {
  1254.     switch (msg)
  1255.     {
  1256.         case WM_ACTIVATE:
  1257.             switch(wParam)
  1258.             {
  1259.                 case WA_ACTIVE:
  1260.                 case WA_CLICKACTIVE:
  1261.                     // Set the cursor extent to this window if we are in render mode because the
  1262.                     // cursor can't be drawn by us when it's not above us.
  1263.                     if (InRenderMode())
  1264.                     {
  1265.                         RECT rc;
  1266.                         GetWindowRect(m_hWnd, &rc);
  1267.                         ClipCursor(&rc);
  1268.                     }
  1269.                     // Reacquire current device
  1270.                     if (GetNumElements() && m_CurSel >= 0)
  1271.                         GetElement(m_CurSel).pPage->Reacquire();
  1272.                     break;
  1273.                 case WA_INACTIVE:
  1274.                     // Unacquire current device
  1275.                     if (GetNumElements() && m_CurSel >= 0)
  1276.                         GetElement(m_CurSel).pPage->Unacquire();
  1277.                     break;
  1278.             }
  1279.             break;
  1280.  
  1281.         case WM_DIRENDER:
  1282.             // Render message, sent by TimerProc() earlier.
  1283.             // The timer proc has request a render operation.
  1284.             Render(m_bNeedRedraw);
  1285.  
  1286.             // Set the next timer event.
  1287.             if (g_fptimeSetEvent)
  1288.                 g_fptimeSetEvent(20, 20, CConfigWnd::TimerProc,
  1289.                                  (DWORD_PTR)m_hWnd, TIME_ONESHOT);
  1290.             return 0;
  1291.  
  1292.         case WM_SETFOCUS:
  1293.             // Set the keyboard focus to the current page window.
  1294.             ShowPage(m_CurSel);  // Call Show() on current page so it can get keyboard focus.
  1295.             return 0;
  1296.  
  1297.         // WM_NCHITTEST handler is added to support moving window when in GDI mode.
  1298.         case WM_NCHITTEST:
  1299.         {
  1300.             if (InRenderMode()) break;
  1301.  
  1302.             BOOL bHitCaption = TRUE;
  1303.             POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
  1304.             int i;
  1305.  
  1306.             ScreenToClient(m_hWnd, &point);
  1307.             // check scroll tab buttons
  1308.             if (m_bScrollTabs)
  1309.                 for (i = 0; i < 2; i++)
  1310.                 {
  1311.                     RECT &r = !i ? m_rectSTRight : m_rectSTLeft;
  1312.                     BOOL b = !i ? m_bScrollTabsRight : m_bScrollTabsLeft;
  1313.                     if (PtInRect(&r, point))
  1314.                     {
  1315.                         if (b)
  1316.                             bHitCaption = FALSE;
  1317.                         break;
  1318.                     }
  1319.                 }
  1320.  
  1321.             // check tabs
  1322.             for (i = 0; i < GetNumElements(); i++)
  1323.                 if (PtInRect(&(GetElement(i).rect), point))
  1324.                 {
  1325.                     bHitCaption = FALSE;
  1326.                     break;
  1327.                 }
  1328.  
  1329.             // check buttons
  1330.             for (i = 0; i < NUMBUTTONS; i++)
  1331.                 if (PtInRect(&(m_Button[i].rect), point))
  1332.                 {
  1333.                     if ((i == BUTTON_RESET || i == BUTTON_OK) && !m_uig.InEditMode()) continue;
  1334.                     bHitCaption = FALSE;
  1335.                     break;
  1336.                 }
  1337.  
  1338.             // Check Y coordinate to see if it is within the caption bar.
  1339.             if ((point.y < GetElement(0).rect.top || point.y > GetElement(0).rect.bottom) &&
  1340.                     (point.y < m_rectBottomGradient.top || point.y > m_rectBottomGradient.bottom))
  1341.                 bHitCaption = FALSE;
  1342.  
  1343.             if (bHitCaption)
  1344.             {
  1345.                 // If we are returning HTCAPTION, clear the page's info box.
  1346.                 GetElement(m_CurSel).pPage->SetInfoText(-1);
  1347.                 return HTCAPTION;
  1348.             }
  1349.             break;
  1350.         }
  1351.  
  1352.         case WM_CFGUIRESET:
  1353.         {
  1354.             CFlexWnd::s_ToolTip.SetEnable(FALSE);
  1355.             m_bHourGlass = TRUE;  // Set the flag so Render() will draw hourglass instead of arrow
  1356.             Invalidate();
  1357.             SendMessage(this->m_hWnd, WM_PAINT, 0, 0);
  1358.             if (InRenderMode())  // If in render mode, need to specifically call OnRender as sending WM_PAINT merely changes flag.
  1359.                 Render(TRUE);
  1360.             if (!Init(CFGWND_INIT_REINIT | CFGWND_INIT_RESET))
  1361.             {
  1362.                 m_uig.SetFinalResult(E_FAIL);
  1363.                 Destroy();
  1364.             }
  1365.             m_bHourGlass = FALSE;  // Change cursor back to arrow
  1366.             m_MsgBox.Destroy();
  1367.             Invalidate();
  1368.             return TRUE;
  1369.         }
  1370.  
  1371.         case WM_SETCURSOR:
  1372.             {
  1373.                 static HCURSOR hCursor = LoadCursor(NULL, IDC_ARROW);
  1374.                 ::SetCursor(InRenderMode() ? NULL : hCursor);
  1375.             }
  1376.             return TRUE;
  1377.  
  1378. //        case WM_QUERYACTIONASSIGNEDANYWHERE:
  1379. //            return IsActionAssignedAnywhere(int(wParam), int(lParam));
  1380.     }
  1381.  
  1382.     return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  1383. }
  1384.  
  1385. HRESULT CConfigWnd::Apply()
  1386. {
  1387.     tracescope(ts, _T("\n\nApplying Changes to All Devices...\n"));
  1388.  
  1389.     // Devices need to be in the unaquired state when SetActionMap is called.
  1390.     Unacquire();
  1391.  
  1392.     for (int i = 0; i < GetNumElements(); i++)
  1393.         GetElement(i).Apply();
  1394.  
  1395.     Reacquire();
  1396.  
  1397.     trace(_T("\n\n"));
  1398.  
  1399.     return S_OK;
  1400. }
  1401.  
  1402. int CConfigWnd::GetNumElements()
  1403. {
  1404.     return m_Element.GetSize();
  1405. }
  1406.  
  1407. ELEMENT &CConfigWnd::GetElement(int i)
  1408. {
  1409.     if (i < 0 || i >= GetNumElements())
  1410.     {
  1411.         assert(0);
  1412.         etrace1(_T("Tried to get invalid element %d\n"), i);
  1413.         return m_InvalidElement;
  1414.     }
  1415.  
  1416.     return m_Element[i];
  1417. }
  1418.  
  1419. // This function returns a pointer to the action format of the device that has the given GUID
  1420. HRESULT CConfigWnd::GetActionFormatFromInstanceGuid(LPDIACTIONFORMATW *lplpAcFor, REFGUID Guid)
  1421. {
  1422.     if (!lplpAcFor)
  1423.         return E_INVALIDARG;
  1424.  
  1425.     for (int i = 0; i < GetNumElements(); i++)
  1426.     {
  1427.         ELEMENT &e = m_Element[i];
  1428.  
  1429.         if (e.didi.guidInstance == Guid)
  1430.         {
  1431.             *lplpAcFor = GetCurAcFor(e);
  1432.             return S_OK;
  1433.         }
  1434.     }
  1435.  
  1436.     return E_INVALIDARG;
  1437. }
  1438.  
  1439. HDC CConfigWnd::GetRenderDC()
  1440. {
  1441.     assert(InRenderMode());
  1442.  
  1443.     if (m_bRender3D)
  1444.         return m_pbm3D == NULL ? NULL : m_pbm3D->BeginPaintInto();
  1445.     else
  1446.     {
  1447.         if (m_pSurface == NULL)
  1448.             return NULL;
  1449.  
  1450.         HDC hDC = NULL;
  1451.         HRESULT hr = m_pSurface->GetDC(&hDC);
  1452.         if (FAILED(hr))
  1453.             if (hr == DDERR_SURFACELOST)
  1454.             {
  1455.                 m_pSurface->Restore();    // Restore the surface
  1456.                 hr = m_pSurface->GetDC(&hDC);  // Retry
  1457.                 if (FAILED(hr))
  1458.                     return NULL;
  1459.             }
  1460.             else
  1461.                 return NULL;
  1462.  
  1463.         return hDC;
  1464.     }
  1465. }
  1466.  
  1467. void CConfigWnd::ReleaseRenderDC(HDC &phDC)
  1468. {
  1469.     assert(InRenderMode());
  1470.  
  1471.     HDC hDC = phDC;
  1472.     phDC = NULL;
  1473.  
  1474.     if (m_bRender3D)
  1475.     {
  1476.         if (m_pbm3D == NULL)
  1477.             return;
  1478.  
  1479.         m_pbm3D->EndPaintInto(hDC);
  1480.     }
  1481.     else
  1482.     {
  1483.         if (m_pSurface == NULL)
  1484.             return;
  1485.  
  1486.         m_pSurface->ReleaseDC(hDC);
  1487.     }
  1488. }
  1489.  
  1490. struct BITMAPINFO_3MASKS
  1491. {
  1492.     BITMAPINFOHEADER bmiHeader;
  1493.     RGBQUAD          bmiColors[3];
  1494. };
  1495.  
  1496. void CConfigWnd::Create3DBitmap()
  1497. {
  1498.     HDC hDC = CreateCompatibleDC(NULL);
  1499.  
  1500.     BITMAPINFO_3MASKS bmi3mask;  // BITMAPINFO with 3 DWORDs for bmiColors
  1501.     BITMAPINFO *pbmi = (BITMAPINFO*)&bmi3mask;
  1502.  
  1503.     BITMAPINFOHEADER &h = pbmi->bmiHeader;
  1504.     h.biSize = sizeof(BITMAPINFOHEADER);
  1505.     h.biWidth = WINDOW_WIDTH;
  1506.     h.biHeight = -WINDOW_HEIGHT;
  1507.     h.biPlanes = 1;
  1508.     h.biSizeImage = 0;
  1509.     h.biXPelsPerMeter = 100;
  1510.     h.biYPelsPerMeter = 100;
  1511.     h.biClrImportant = 0;
  1512.  
  1513.     // Get the surface's pixel format
  1514.     D3DSURFACE_DESC d3dsd;
  1515.     ZeroMemory(&d3dsd, sizeof(d3dsd));
  1516.     m_pSurface3D->GetDesc(&d3dsd);
  1517.     m_SurfFormat = d3dsd.Format;
  1518.     switch(d3dsd.Format)
  1519.     {
  1520.         case D3DFMT_R5G6B5:
  1521.             h.biClrUsed = 3;
  1522.             h.biBitCount = 16;
  1523.             m_uiPixelSize = 2;
  1524.             h.biCompression = BI_BITFIELDS;
  1525.             *((LPDWORD)pbmi->bmiColors) = 0xF800;
  1526.             *((LPDWORD)pbmi->bmiColors+1) = 0x07E0;
  1527.             *((LPDWORD)pbmi->bmiColors+2) = 0x001F;
  1528.             break;
  1529.  
  1530.         case D3DFMT_X1R5G5B5:
  1531.         case D3DFMT_A1R5G5B5:
  1532.             h.biClrUsed = 3;
  1533.             h.biBitCount = 16;
  1534.             m_uiPixelSize = 2;
  1535.             h.biCompression = BI_BITFIELDS;
  1536.             *((LPDWORD)pbmi->bmiColors) = 0x7C00;
  1537.             *((LPDWORD)pbmi->bmiColors+1) = 0x03E0;
  1538.             *((LPDWORD)pbmi->bmiColors+2) = 0x001F;
  1539.             break;
  1540.  
  1541.         case D3DFMT_R8G8B8:
  1542.             h.biClrUsed = 0;
  1543.             h.biBitCount = 24;
  1544.             m_uiPixelSize = 3;
  1545.             h.biCompression = BI_RGB;
  1546.             break;
  1547.  
  1548.         case D3DFMT_A8R8G8B8:
  1549.         case D3DFMT_X8R8G8B8:
  1550.         default:
  1551.             // Use 32 bits for all other formats
  1552.             h.biClrUsed = 0;
  1553.             h.biBitCount = 32;
  1554.             m_uiPixelSize = 4;
  1555.             h.biCompression = BI_RGB;
  1556.             break;
  1557.     }
  1558.  
  1559.     HBITMAP hbm = CreateDIBSection(
  1560.         hDC,
  1561.         pbmi,
  1562.         DIB_RGB_COLORS,
  1563.         &m_p3DBits,
  1564.         NULL,
  1565.         0);
  1566.  
  1567.     DeleteDC(hDC);
  1568.     hDC = NULL;
  1569.  
  1570.     if (hbm != NULL)
  1571.         m_pbm3D = CBitmap::StealToCreate(hbm);
  1572.  
  1573.     if (hbm != NULL)
  1574.         DeleteObject((HGDIOBJ)hbm);
  1575.     hbm = NULL;
  1576. }
  1577.  
  1578. void CConfigWnd::Copy3DBitmapToSurface3D()
  1579. {
  1580.     assert(m_bRender3D);
  1581.  
  1582.     if (m_p3DBits == NULL || m_pbm3D == NULL || m_pSurface3D == NULL)
  1583.     {
  1584.         etrace(_T("One or more of the vars required for Copy3DBitmapToSurface() was NULL!\n"));
  1585.         return;
  1586.     }
  1587.  
  1588.     RECT rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
  1589.  
  1590.     HRESULT hr = D3DXLoadSurfaceFromMemory(
  1591.         m_pSurface3D,
  1592.         NULL,
  1593.         NULL,//&rect,
  1594.         m_p3DBits,
  1595.         m_SurfFormat,
  1596.         WINDOW_WIDTH * m_uiPixelSize,
  1597.         NULL,
  1598.         &rect,
  1599.         D3DX_FILTER_POINT,
  1600.         0);  // Disable Color Key
  1601. }
  1602.  
  1603. void CConfigWnd::CallRenderCallback()
  1604. {
  1605.     LPDICONFIGUREDEVICESCALLBACK pCallback = m_uig.GetCallback();
  1606.     LPVOID pvRefData = m_uig.GetRefData();
  1607.  
  1608.     if (pCallback == NULL)
  1609.         return;
  1610.  
  1611.     if (m_bRender3D)
  1612.     {
  1613.         Copy3DBitmapToSurface3D();
  1614.         pCallback(m_pSurface3D, pvRefData);
  1615.     }
  1616.     else
  1617.     {
  1618.         pCallback(m_pSurface, pvRefData);
  1619.     }
  1620. }
  1621.  
  1622. void CConfigWnd::OnRender(BOOL bInternalCall)
  1623. {
  1624.     m_bNeedRedraw = TRUE;
  1625. }
  1626.  
  1627. void CConfigWnd::Render(BOOL bInternalCall)
  1628. {
  1629.     tracescope(__ts, _T("CConfigWnd::Render() "));
  1630.     traceBOOL(bInternalCall);
  1631.  
  1632.     m_bNeedRedraw = FALSE;
  1633.  
  1634.     ValidateRect(m_hWnd, NULL);
  1635.  
  1636.     if (m_hWnd == NULL)
  1637.         return;
  1638.  
  1639.     HDC hDC = GetRenderDC();
  1640.     if (hDC == NULL)
  1641.         return;
  1642.  
  1643.     if (bInternalCall)
  1644.         RenderInto(hDC);
  1645.  
  1646.     static ICONINFO IconInfo;
  1647.     static HCURSOR hOldCursor = NULL;
  1648.     static HCURSOR hCursor;
  1649.     if (m_bHourGlass)
  1650.         hCursor = LoadCursor(NULL, IDC_WAIT);
  1651.     else
  1652.         hCursor = LoadCursor(NULL, IDC_ARROW);
  1653.     if (hCursor == NULL)
  1654.         return;
  1655.  
  1656.     if (hOldCursor != hCursor)
  1657.     {
  1658.         hOldCursor = hCursor;
  1659.         GetIconInfo(hCursor, &IconInfo);
  1660.  
  1661.         if (IconInfo.hbmMask)
  1662.             DeleteObject(IconInfo.hbmMask);
  1663.  
  1664.         if (IconInfo.hbmColor)
  1665.             DeleteObject(IconInfo.hbmColor);
  1666.     }
  1667.  
  1668.     POINT pt;
  1669.     GetCursorPos(&pt);
  1670.  
  1671.     ScreenToClient(m_hWnd, &pt);
  1672.  
  1673.     pt.x -= IconInfo.xHotspot;
  1674.     pt.y -= IconInfo.yHotspot;
  1675.  
  1676.     if (m_pbmPointerEraser)
  1677.         m_pbmPointerEraser->Get(hDC, pt);
  1678.  
  1679.     // If m_bHourGlass is true, we are resetting, so we don't draw mouse cursor.
  1680.     if (hCursor && !m_bHourGlass)
  1681.         DrawIcon(hDC, pt.x, pt.y, hCursor);
  1682.  
  1683.     ReleaseRenderDC(hDC);
  1684.  
  1685.     CallRenderCallback();
  1686.  
  1687.     hDC = GetRenderDC();
  1688.     if (hDC == NULL)
  1689.         return;
  1690.  
  1691.     if (m_pbmPointerEraser)
  1692.         m_pbmPointerEraser->Draw(hDC, pt);
  1693.  
  1694.     ReleaseRenderDC(hDC);
  1695. }
  1696.  
  1697. void CConfigWnd::Unacquire()
  1698. {
  1699.     for (int i = 0; i < GetNumElements(); i++)
  1700.     {
  1701.         ELEMENT &e = m_Element[i];
  1702.         if (e.pPage != NULL)
  1703.             e.pPage->Unacquire();
  1704.     }
  1705. }
  1706.  
  1707. void CConfigWnd::Reacquire()
  1708. {
  1709.     for (int i = 0; i < GetNumElements(); i++)
  1710.     {
  1711.         ELEMENT &e = m_Element[i];
  1712.         if (e.pPage != NULL)
  1713.             e.pPage->Reacquire();
  1714.     }
  1715. }
  1716.  
  1717. HRESULT CConfigWnd::Reset()
  1718. {
  1719.     RECT rect;
  1720.     int iCenterX, iCenterY;
  1721.  
  1722.     GetClientRect(&rect);
  1723.     iCenterX = (rect.left + rect.right) >> 1;
  1724.     iCenterY = (rect.top + rect.bottom) >> 1;
  1725.     rect.left = rect.right = iCenterX;
  1726.     rect.top = rect.bottom = iCenterY;
  1727.     InflateRect(&rect, g_iResetMsgBoxWidth >> 1, g_iResetMsgBoxHeight >> 1);
  1728.  
  1729.     m_MsgBox.Create(m_hWnd, rect, FALSE);
  1730.     m_MsgBox.SetNotify(m_hWnd);
  1731.     m_MsgBox.SetFont((HFONT)m_uig.GetFont(UIE_USERNAMES));
  1732.     m_MsgBox.SetColors(m_uig.GetTextColor(UIE_USERNAMES),
  1733.                            m_uig.GetBkColor(UIE_USERNAMES),
  1734.                            m_uig.GetTextColor(UIE_USERNAMESEL),
  1735.                            m_uig.GetBkColor(UIE_USERNAMESEL),
  1736.                            m_uig.GetBrushColor(UIE_USERNAMES),
  1737.                            m_uig.GetPenColor(UIE_USERNAMES));
  1738.  
  1739.     TCHAR tszResourceString[MAX_PATH];
  1740.     LoadString(g_hModule, IDS_RESETMSG, tszResourceString, MAX_PATH);
  1741.     m_MsgBox.SetText(tszResourceString);
  1742.     ::ShowWindow(m_MsgBox.m_hWnd, SW_SHOW);
  1743.     ::SetWindowPos(m_MsgBox.m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
  1744.     m_MsgBox.Invalidate();
  1745.     return S_OK;
  1746. }
  1747.  
  1748. HRESULT CConfigWnd::QueryActionAssignedAnywhere(GUID GuidInstance, int i)
  1749. {
  1750.     return IsActionAssignedAnywhere(GuidInstance, i) ? S_OK : S_FALSE;
  1751. }
  1752.  
  1753. int CConfigWnd::GetNumGenres()
  1754. {
  1755.     return m_uig.GetNumMasterAcFors();
  1756. }
  1757.  
  1758. HRESULT CConfigWnd::SetCurUser(int nPage, int nUser)
  1759. {
  1760.     // make sure we're using a valid element index
  1761.     if (nPage < 0 || nPage >= GetNumElements())
  1762.     {
  1763.         assert(0);
  1764.         return E_FAIL;
  1765.     }
  1766.  
  1767.     // get the element
  1768.     ELEMENT &e = GetElement(nPage);
  1769.     
  1770.     // don't do anything if we're already set to this user
  1771.     if (e.nCurUser == nUser)
  1772.         return S_OK;
  1773.  
  1774.     // store new curuser
  1775.     e.nCurUser = nUser;
  1776.  
  1777.     // if this page isn't the one currently shown, do nothing
  1778.     // (it'll get the new acfor when it's shown)
  1779.     if (m_CurSel != nPage)
  1780.         return S_OK;
  1781.  
  1782.     // otherwised, cycle the page to reflect change
  1783.     if (e.pPage)
  1784.         e.pPage->Unacquire();
  1785.     HidePage(nPage);
  1786.     ShowPage(nPage);
  1787.     if (e.pPage)
  1788.         e.pPage->Reacquire();
  1789.  
  1790.     return S_OK;
  1791. }
  1792.  
  1793. HRESULT CConfigWnd::SetCurGenre(int NewGenre)
  1794. {
  1795.     // if no change, do nothing
  1796.     if (NewGenre == m_nCurGenre)
  1797.         return S_OK;
  1798.  
  1799.     // make sure genre index is in range
  1800.     if (NewGenre < 0 || NewGenre >= GetNumGenres())
  1801.         return E_INVALIDARG;
  1802.  
  1803.     // set genre
  1804.     m_nCurGenre = NewGenre;
  1805.  
  1806.     // store which page is currently up
  1807.     int iOldPage = m_CurSel;
  1808.  
  1809.     // for each page...
  1810.     BOOL bShown = FALSE;
  1811.     for (int i = 0; i < GetNumElements(); i++)
  1812.     {
  1813.         ELEMENT &e = GetElement(i);
  1814.  
  1815.         // hide the page and unacquire its device
  1816.         if (e.pPage)
  1817.         {
  1818.             e.pPage->Unacquire();
  1819.             HidePage(i);
  1820.         }
  1821.  
  1822.         // show page if it was the old cur page
  1823.         if (i == iOldPage && e.pPage && GetCurAcFor(e))
  1824.         {
  1825.             ShowPage(i);
  1826.             bShown = TRUE;
  1827.         }
  1828.  
  1829.         // reacquire device
  1830.         if (e.pPage)
  1831.             e.pPage->Reacquire();
  1832.     }
  1833.  
  1834.     // if nothing was shown, show something
  1835.     if (!bShown && GetNumElements() > 0)
  1836.     {
  1837.         m_CurSel = -1;
  1838.         SelTab(0);
  1839.     }
  1840.  
  1841.     // if we showed the one we expected to show, we succeeded
  1842.     return bShown ? S_OK : E_FAIL;
  1843. }
  1844.  
  1845. int CConfigWnd::GetCurGenre()
  1846. {
  1847.     return m_nCurGenre;
  1848. }
  1849.  
  1850. HWND CConfigWnd::GetMainHWND()
  1851. {
  1852.     return m_hWnd;
  1853. }
  1854.  
  1855. // This is called by CDIDeviceActionConfigPage::DeviceUINotify.
  1856. // We scan the ELEMENT array and when we find a match, destroy and recreate the device
  1857. // object, then return it back to CDIDeviceActionConfigPage so it can update its pointer.
  1858. LPDIRECTINPUTDEVICE8W CConfigWnd::RenewDevice(GUID &GuidInstance)
  1859. {
  1860.     for (int i = 0; i < GetNumElements(); i++)
  1861.     {
  1862.         ELEMENT &e = GetElement(i);
  1863.  
  1864.         if (e.didi.guidInstance == GuidInstance)
  1865.         {
  1866.             // Releaes the instance we have
  1867.             if (e.lpDID)
  1868.             {
  1869.                 e.lpDID->Release();
  1870.                 e.lpDID = NULL;
  1871.             }
  1872.             // Recreate the device
  1873.             e.lpDID = CreateDevice(e.didi.guidInstance);
  1874.             return e.lpDID;
  1875.         }
  1876.     }
  1877.     return NULL;
  1878. }
  1879.  
  1880. LPDIACTIONFORMATW ELEMENT::GetAcFor(int nGenre, int nUser, BOOL bHwDefault)
  1881. {
  1882.     // return null if requesting for unassigned user
  1883.     if (nUser == -1)
  1884.         return NULL;
  1885.  
  1886.     // validate params
  1887.     if (!lpDID || !pUIGlobals || nGenre < 0 ||
  1888.         nGenre >= pUIGlobals->GetNumMasterAcFors() ||
  1889.         nUser < 0 || nUser >= pUIGlobals->GetNumUserNames())
  1890.     {
  1891.         etrace(_T("ELEMENT::GetAcFor(): Invalid params\n"));
  1892.         return NULL;
  1893.     }
  1894.  
  1895.     // generate dword id for map entry
  1896.     DWORD dwMap = GENREUSER2MAP(nGenre, nUser);
  1897.  
  1898.     // try to get that acfor
  1899.     LPDIACTIONFORMATW lpAcFor = NULL;
  1900.     BOOL bFound = AcForMap.Lookup(dwMap, lpAcFor);
  1901.  
  1902.     // if we found it and its not null and we are asked for hardware default setting, return it
  1903.     if (bFound && lpAcFor && !bHwDefault)
  1904.         return lpAcFor;
  1905.  
  1906.     // otherwise...  we gotta make it
  1907.     tracescope(__ts, _T("ELEMENT::GetAcFor"));
  1908.     trace2(_T("(%d, %d)\n"), nGenre, nUser);
  1909.     trace1(_T("Building map entry 0x%08x...\n"), dwMap);
  1910.  
  1911.     // copy it from the masteracfor for the genre
  1912.     lpAcFor = DupActionFormat(&(pUIGlobals->RefMasterAcFor(nGenre)));
  1913.     if (!lpAcFor)
  1914.     {
  1915.         etrace(_T("DupActionFormat() failed\n"));
  1916.         return NULL;
  1917.     }
  1918.  
  1919.     // build it for the user
  1920.     DWORD dwFlags = 0;
  1921.     if (bHwDefault
  1922.        )
  1923.         dwFlags |= DIDBAM_HWDEFAULTS;
  1924.     LPCWSTR wszUserName = pUIGlobals->GetUserName(nUser);
  1925.     HRESULT hr = lpDID->BuildActionMap(lpAcFor, wszUserName, dwFlags);
  1926.     if (FAILED(hr))
  1927.     {
  1928.         etrace4(_T("BuildActionMap(0x%p, %s, 0x%08x) failed, returning 0x%08x\n"), lpAcFor, QSAFESTR(wszUserName), dwFlags, hr);
  1929.         FreeActionFormatDup(lpAcFor);
  1930.         lpAcFor = NULL;
  1931.         return NULL;
  1932.     }
  1933.     else
  1934.     {
  1935.         trace3(_T("BuildActionMap(0x%p, %s, 0x%08x) succeeded\n"), lpAcFor, QSAFESTR(wszUserName), dwFlags);
  1936.         // Now we check if the return code is DI_WRITEPROTECT.  If so, device can't be remapped.
  1937.         if (hr == DI_WRITEPROTECT)
  1938.         {
  1939.             // The way we disable mapping is to add DIA_APPFIXED flag to all actions.
  1940.             for (DWORD i = 0; i < lpAcFor->dwNumActions; ++i)
  1941.                 lpAcFor->rgoAction[i].dwFlags |= DIA_APPFIXED;
  1942.         }
  1943.     }
  1944.  
  1945.     // Here we copy the DIA_APPFIXED flag back to our action format for all DIACTION that had this.
  1946.     const DIACTIONFORMATW &MasterAcFor = pUIGlobals->RefMasterAcFor(nGenre);
  1947.     for (DWORD i = 0; i < MasterAcFor.dwNumActions; ++i)
  1948.         if (MasterAcFor.rgoAction[i].dwFlags & DIA_APPFIXED)
  1949.             lpAcFor->rgoAction[i].dwFlags |= DIA_APPFIXED;
  1950.     // set it in the map
  1951.     assert(lpAcFor != NULL);
  1952.     AcForMap.SetAt(dwMap, lpAcFor);
  1953.  
  1954.     // return it
  1955.     return lpAcFor;
  1956. }
  1957.  
  1958. void ELEMENT::FreeMap()
  1959. {
  1960.     POSITION pos = AcForMap.GetStartPosition();
  1961.     while (pos != NULL)
  1962.     {
  1963.         DWORD dwMap = (DWORD)-1;
  1964.         LPDIACTIONFORMATW lpAcFor = NULL;
  1965.         AcForMap.GetNextAssoc(pos, dwMap, lpAcFor);
  1966.  
  1967.         if (lpAcFor)
  1968.             FreeActionFormatDup(lpAcFor);
  1969.     }
  1970.     AcForMap.RemoveAll();
  1971. }
  1972.  
  1973. void ELEMENT::Apply()
  1974. {
  1975.     tracescope(tsa, _T("\nELEMENT::Apply()\n"));
  1976.     trace1(_T("Applying Changes to Device %s\n"), QSAFESTR(didi.tszInstanceName));
  1977.  
  1978.     if (lpDID == NULL)
  1979.     {
  1980.         etrace(_T("NULL lpDID, can't apply\n"));
  1981.         return;
  1982.     }
  1983.  
  1984.     if (pUIGlobals == NULL)
  1985.     {
  1986.         etrace(_T("NULL pUIGlobals, can't apply\n"));
  1987.         return;
  1988.     }
  1989.  
  1990.     LPDIACTIONFORMATW lpAcFor = NULL;
  1991.  
  1992.     // go through the map and add the map keys to last if the user
  1993.     // is the current user assignment, or to first if not
  1994.     CList<DWORD, DWORD &> first, last;
  1995.     POSITION pos = AcForMap.GetStartPosition();
  1996.     while (pos != NULL)
  1997.     {
  1998.         DWORD dwMap = (DWORD)-1;
  1999.         lpAcFor = NULL;
  2000.         AcForMap.GetNextAssoc(pos, dwMap, lpAcFor);
  2001.         
  2002.         if (MAP2USER(dwMap) == nCurUser)
  2003.             last.AddTail(dwMap);
  2004.         else
  2005.             first.AddTail(dwMap);
  2006.     }
  2007.  
  2008.     // concatenate lists
  2009.     first.AddTail(&last);
  2010.  
  2011.     // now go through the resulting list (so that the current
  2012.     // assignments are set last) if this device is assigned.
  2013.     if (nCurUser != -1)
  2014.     {
  2015.         pos = first.GetHeadPosition();
  2016.         while (pos != NULL)
  2017.         {
  2018.             DWORD dwMap = first.GetNext(pos);
  2019.             lpAcFor = AcForMap[dwMap];
  2020.  
  2021.             tracescope(tsa2, _T("Applying lpAcFor at AcForMap["));
  2022.             trace1(_T("0x%08x]...\n"), dwMap);
  2023.  
  2024.             if (lpAcFor == NULL)
  2025.             {
  2026.                 etrace(_T("NULL lpAcFor, can't apply\n"));
  2027.                 continue;
  2028.             }
  2029.  
  2030.             int nGenre = MAP2GENRE(dwMap);
  2031.             int nUser = MAP2USER(dwMap);
  2032.             LPCWSTR wszUserName = pUIGlobals->GetUserName(nUser);
  2033.  
  2034.             traceLONG(nGenre);
  2035.             traceLONG(nUser);
  2036.             traceWSTR(wszUserName);
  2037.  
  2038.             TraceActionFormat(_T("Final Device ActionFormat:"), *lpAcFor);
  2039.  
  2040.             for (DWORD j = 0; j < lpAcFor->dwNumActions; ++j)
  2041.             {
  2042.                 if( lpAcFor->rgoAction[j].dwObjID == (DWORD)-1 || IsEqualGUID(lpAcFor->rgoAction[j].guidInstance, GUID_NULL))
  2043.                 { 
  2044.                     lpAcFor->rgoAction[j].dwHow = DIAH_UNMAPPED;
  2045.                 }
  2046.                 else if( lpAcFor->rgoAction[j].dwHow & 
  2047.                         ( DIAH_USERCONFIG | DIAH_APPREQUESTED | DIAH_HWAPP | DIAH_HWDEFAULT | DIAH_DEFAULT ) )
  2048.                 {
  2049.                     lpAcFor->rgoAction[j].dwHow = DIAH_USERCONFIG;
  2050.                 }
  2051.                 else if(IsEqualGUID(didi.guidInstance,lpAcFor->rgoAction[j].guidInstance))
  2052.                 {
  2053.                     lpAcFor->rgoAction[j].dwHow = DIAH_USERCONFIG;
  2054.                 }
  2055.             }
  2056.  
  2057.             HRESULT hr;
  2058.             hr = lpDID->SetActionMap(lpAcFor, wszUserName, DIDSAM_FORCESAVE|DIDSAM_DEFAULT);
  2059.  
  2060.             if (FAILED(hr))
  2061.                 etrace1(_T("SetActionMap() failed, returning 0x%08x\n"), hr);
  2062.             else
  2063.                 trace(_T("SetActionMap() succeeded\n"));
  2064.         }
  2065.     }  // if (nCurUser != -1)
  2066.     else
  2067.     {
  2068.         // we're unassigned, set null
  2069.         trace(_T("Unassigning...\n"));
  2070.  
  2071.         // we need an acfor to unassign, so get one if don't have
  2072.         // one left over from what we just did
  2073.         if (!lpAcFor)
  2074.             lpAcFor = GetAcFor(0, 0);
  2075.  
  2076.         if (!lpAcFor)
  2077.             etrace(_T("Couldn't get an acfor for unassignment\n"));
  2078.  
  2079.         HRESULT hr;
  2080.         hr = lpDID->SetActionMap(lpAcFor, NULL, DIDSAM_NOUSER);
  2081.  
  2082.         if (FAILED(hr))
  2083.             etrace1(_T("SetActionMap() failed, returning 0x%08x\n"), hr);
  2084.         else
  2085.             trace(_T("SetActionMap() succeeded\n"));
  2086.     }
  2087. }
  2088.  
  2089. int CConfigWnd::GetNumUsers()
  2090. {
  2091.     return m_uig.GetNumUserNames();
  2092. }
  2093.  
  2094. int    CConfigWnd::GetCurUser(int nPage)
  2095. {
  2096.     return GetElement(nPage).nCurUser;
  2097. }
  2098.